
/*
 * sndpipe: A UNIX pipes-based audio stream processor toolkit.
 * Copyright (C) 2011  Bradley Worley
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to:
 *
 *   Free Software Foundation, Inc.
 *   51 Franklin Street, Fifth Floor
 *   Boston, MA  02110-1301, USA.
 */

/* include the sndpipe header. */
#include "sndpipe.h"

/* define the default rollover value for printing messages. */
#define SP_PAS_ROLLOVER 32768

/* func_pas: initiates the PAS functionality.
 *
 * this function opens up an input and output pipe (both are required)
 * and prints periodic status messages relating to stream information
 * and performance statistics.
 */
void func_pas (void) {
  /* declare required variables. */
  unsigned long n, rollover, frames;
  struct pipes *pi, *po;
  double **buf, dt;
  SF_INFO sfi;

  /* declare required timing variables. */
  time_t t0, t1;

  /* zero out the sndfile information structure. */
  memset (&sfi, 0, sizeof (sfi));

  /* attempt to open the input pipe. */
  pi = pipes_open_input ();

  /* ensure the input pipe was successfully opened. */
  if (!pi) {
    /* print a failure message and exit the application. */
    failf ("unable to open input pipe");
  }

  /* set the output pipe options directly from the input pipe. */
  sfi.samplerate = pi->sfi.samplerate;
  sfi.channels = pi->sfi.channels;
  sfi.format = pi->sfi.format;

  /* ensure we have an output format. */
  if (!sfi.format) {
    /* print a failure message and exit the application. */
    failf ("unable to retrieve pipes output format");
  }

  /* open the output pipes structure and allocate the buffer memory. */
  frames = 0;
  po = pipes_open_output (sfi);
  buf = pipes_buf_alloc (po, &frames);

  /* print an initial message about general audio stream info. */
  fprintf (stderr, "sndpipe[PAS]: Streaming %d channel%s at %d khz\n",
    po->sfi.channels, po->sfi.channels > 1 ? "s" : "", po->sfi.samplerate);

  /* initialize the rollover counter and the time value. */
  n = 0;
  rollover = SP_PAS_ROLLOVER;
  t0 = time (NULL);

  /* loop while we can write samples to the pipe. */
  do {
    /* attempt to read from the input pipe. */
    if (pipes_read (pi, &buf, frames) != SP_OK) {
      /* print a failure message and break the loop. */
      warnf ("unable to read from input audio pipe");
      break;
    }

    /* increment the counter. */
    n++;

    /* are we at a rollover-inducing count? */
    if (n == rollover) {
      /* calculate the elapsed time. */
      t1 = time (NULL);
      dt = (double) t1 - (double) t0;

      /* print the timing statistics to standard error. */
      fprintf (stderr,
        "sndpipe[PAS]: Processed %.2le frames in %lu seconds (%.2le fps)\n",
        (double) frames * (double) rollover, (unsigned long) dt,
        (double) frames * (double) rollover / dt);

      /* flush the standard error. */
      fflush (stderr);

      /* tweak the rollover value for optimal refresh rate. */
      if (dt > 10.0) rollover *= 0.7;
      else if (dt < 1.0) rollover /= 0.7;

      /* get ready for the next rollover. */
      t0 = t1;
      n = 0;
    }
  } while (pipes_write (po, buf, frames) == SP_OK);

  /* free the output pipes buffer memory. */
  pipes_buf_free (po, frames, buf);

  /* attempt to close the input pipe. */
  if (pipes_close (pi) != SP_OK) {
    /* print a failure message and exit the application. */
    failf ("unable to close input pipe");
  }

  /* attempt to close the output pipe. */
  if (pipes_close (po) != SP_OK) {
    /* print a failure message and exit the application. */
    failf ("unable to close output pipe");
  }
}

